package refl

import (
	"fmt"
	"reflect"
)

type StructField reflect.StructField

// 获取数据的结构体类型
func StructType(v any) reflect.Type {
	vtype := reflect.TypeOf(v)
	if vtype.Kind() == reflect.Ptr {
		vtype = vtype.Elem()
	}
	return vtype
}

// 获取结构体字段的值
func GetFieldValue(obj any, fieldName string) (any, error) {
	var objValue reflect.Value
	if v, ok := obj.(reflect.Value); !ok {
		objValue = reflect.ValueOf(obj)
	} else {
		objValue = v
	}
	if objValue.Kind() == reflect.Ptr {
		objValue = objValue.Elem()
	}
	if objValue.IsValid() {
		// 确保obj是结构体
		if objValue.Kind() != reflect.Struct {
			return nil, fmt.Errorf("reflect: %#v is not a struct", obj)
		}
		objValue = objValue.FieldByName(fieldName)
		return objValue.Interface(), nil
	}
	return nil, fmt.Errorf("%v is not a valid", objValue)
}

// 使用反射设置结构体字段的值
func SetFieldValue(obj interface{}, fieldName string, value interface{}) error {
	objValue := reflect.ValueOf(obj)
	if objValue.Kind() == reflect.Ptr {
		objValue = objValue.Elem()
	}

	// 确保obj是结构体
	if objValue.Kind() != reflect.Struct {
		return fmt.Errorf("reflect: %#v is not a struct", obj)
	}

	objType := objValue.Type()
	fieldValue := objValue.FieldByName(fieldName)

	// 确保字段存在
	if !fieldValue.IsValid() {
		return fmt.Errorf("reflect: %s is not a field of %s", fieldName, objType.Name())
	}

	// 确保字段是可设置的
	if !fieldValue.CanSet() {
		return fmt.Errorf("reflect: %s is not settable", fieldName)
	}

	// 将输入值的反射值设置给字段
	v := reflect.ValueOf(value)
	if v.Type().AssignableTo(fieldValue.Type()) {
		fieldValue.Set(v)
		return nil
	}

	return fmt.Errorf("reflect: cannot set %s as %s is incompatible type", v.Type(), fieldValue.Type())
}

// 遍历StructField
func IterFields(v interface{}, fn func(f reflect.StructField) error) error {
	vtype := reflect.TypeOf(v)
	if vtype.Kind() == reflect.Ptr {
		vtype = vtype.Elem()
	}
	for i := 0; i < vtype.NumField(); i++ {
		field := vtype.Field(i)
		if err := fn(field); err != nil {
			return err
		}
	}
	return nil
}

// 检查结构体是否实现了接口
func CheckImplements[T any, I any]() bool {
	var t T
	var o any = &t
	if _, ok := o.(I); ok {
		return true
	}
	return false
}
